package com.example.keshe.Dao.impl;

import com.example.keshe.Dao.SaleDao;
import com.example.keshe.Sale;
import com.example.keshe.util.DruidUtil;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * SaleDaoImpl 实现 SaleDao 接口，用于对销售数据进行数据库操作。
 *
 * @param <T> 泛型类型，通常为 Sale 类型
 */
public class SaleDaoImpl<T> implements SaleDao<T> {
    private Connection conn; // 数据库连接对象
    private PreparedStatement pstmt; // 数据库操作对象
    private ExecutorService executorService = Executors.newFixedThreadPool(5); // 线程池，用于异步数据库操作

    /**
     * SaleDaoImpl 构造方法，接受一个数据库连接对象作为参数。
     *
     * @param conn 数据库连接对象
     */
    public SaleDaoImpl(Connection conn) {
        this.conn = conn;
    }

    /**
     * 分页查询销售数据。
     *
     * @param pageIndex 页索引
     * @param pageSize  每页记录数
     * @return 包含销售数据的列表
     * @throws Exception 如果数据库操作出现异常
     */
    @Override
    public List<T> selectByPage(int pageIndex, int pageSize) throws Exception {
        int offset = (pageIndex - 1) * pageSize;// 计算偏移量
        String sql = "SELECT * FROM sale LIMIT ? OFFSET ?";// SQL 查询语句，使用 LIMIT 和 OFFSET 进行分页
        // 使用 try-with-resources 确保 PreparedStatement 能够被正确关闭
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置参数
            pstmt.setInt(1, pageSize);
            pstmt.setInt(2, offset);
            // 使用 try-with-resources 确保 ResultSet 能够被正确关闭
            try (ResultSet rs = pstmt.executeQuery()) {
                // 解析结果集，构建销售对象列表
                List<Sale> saleList = new ArrayList<>();
                while (rs.next()) {
                    saleList.add(new Sale(
                            rs.getString("saleId"),
                            rs.getString("clothingId"),
                            rs.getString("quantitySold"),
                            rs.getString("totalAmount"),
                            rs.getString("remainingStock"),
                            rs.getString("saleDate")
                    ));
                }
                return (List<T>) saleList;
            }
        }
    }

    /**
     * 获取销售表中的总记录数。
     *
     * @return 销售表中的总记录数
     * @throws SQLException 如果数据库操作出现异常
     */
    @Override
    public int getTotalRecords() throws SQLException {
        String sql = "SELECT COUNT(*) FROM sale"; // SQL 查询语句，统计销售表中的总记录数
        // 使用 try-with-resources 确保 PreparedStatement 能够被正确关闭
        try (PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            // 如果查询结果包含数据，返回第一列的值（总记录数）
            if (rs.next()) {
                return rs.getInt(1);
            }
        }
        return 0;// 如果没有数据或发生异常，返回0
    }

    /**
     * 显示信息提示框。
     *
     * @param title       提示框标题
     * @param content     提示框内容
     */
    private void showInformationAlert(String title, String content) {
        showAlert(title, content, Alert.AlertType.INFORMATION);
    }

    /**
     * 显示错误提示框。
     *
     * @param title   提示框标题
     * @param content 提示框内容
     */
    private void showErrorAlert(String title, String content) {
        showAlert(title, content, Alert.AlertType.ERROR);
    }

    /**
     * 弹出提示框。
     *
     * @param title     提示框标题
     * @param content   提示框内容
     * @param alertType 提示框类型
     */
    private void showAlert(String title, String content, Alert.AlertType alertType) {
        Platform.runLater(() -> {
            Alert alert = new Alert(alertType);
            alert.setTitle(title);
            alert.setHeaderText(null);
            alert.setContentText(content);
            alert.showAndWait();
        });
    }

    /**
     * 检查销售ID是否唯一。
     *
     * @param conn   数据库连接对象
     * @param saleId 销售ID
     * @return 如果销售ID唯一，返回 true；否则返回 false
     * @throws SQLException 如果数据库操作出现异常
     */
    private boolean isSaleIdUnique(Connection conn, String saleId) throws SQLException {
        String sql = "SELECT COUNT(*) FROM sale WHERE saleid = ?"; // SQL查询语句，统计符合条件的销售ID数量
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, saleId);// 设置SQL语句中的参数
            try (ResultSet resultSet = pstmt.executeQuery()) {
                // 如果查询结果中有数据
                if (resultSet.next()) {
                    return resultSet.getInt(1) == 0;// 如果销售ID数量为0，表示唯一
                }
            }
        }
        return false;// 如果发生异常或查询结果为空，则返回false
    }

    /**
     * 检查服装ID是否存在。
     *
     * @param conn       数据库连接对象
     * @param clothingId 服装ID
     * @return 如果服装ID存在，返回 true；否则返回 false
     * @throws SQLException 如果数据库操作出现异常
     */
    private boolean isClothingIdValid(Connection conn, String clothingId) throws SQLException {
        String sql = "SELECT COUNT(*) FROM clothing WHERE clothingid = ?";  // SQL查询语句，统计符合条件的服装ID数量
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, clothingId);// 设置SQL语句中的参数
            try (ResultSet resultSet = pstmt.executeQuery()) {
                // 如果查询结果中有数据
                if (resultSet.next()) {
                    return resultSet.getInt(1) > 0;// 如果服装ID数量大于0，表示存在
                }
            }
        }
        return false;// 如果发生异常或查询结果为空，则返回false
    }

    /**
     * 验证输入是否完整。
     *
     * @param sale 销售对象
     * @return 如果输入完整，返回 true；否则返回 false
     */
    private boolean isValidInput(T sale) {
        // 判断输入对象是否为Sale类型
        if (sale instanceof Sale) {
            Sale validSale = (Sale) sale;
            // 检查Sale对象的各属性是否为非空字符串
            return isValidString(validSale.getSaleId()) &&
                    isValidString(validSale.getClothingId()) &&
                    isValidString(validSale.getQuantitySold()) &&
                    isValidString(validSale.getSaleDate());
        }
        return false;// 如果输入对象不是Sale类型，则返回false
    }

    /**
     * 辅助方法，检查字符串是否为非空。
     *
     * @param input 输入字符串
     * @return 如果字符串不为空，返回 true；否则返回 false
     */
    private boolean isValidString(String input) {
        return input != null && !input.trim().isEmpty();// 判断输入字符串是否不为null且去除首尾空格后不为空
    }


    /**
     * 获取 clothing 表中的单价。
     *
     * @param conn       数据库连接对象
     * @param clothingId 服装ID
     * @return 服装的单价
     * @throws SQLException 如果数据库操作出现异常
     */
    private BigDecimal getUnitPrice(Connection conn, String clothingId) throws SQLException {
        BigDecimal unitPrice = BigDecimal.ZERO;// 初始单价为0
        // 使用预处理语句查询 clothing 表中指定 clothingId 的单价
        try (PreparedStatement preparedStatement = conn.prepareStatement("SELECT price FROM clothing WHERE clothingid = ?")) {
            preparedStatement.setString(1, clothingId);// 设置 SQL 语句中的参数
            // 执行查询并获取结果集
            try (ResultSet resultSet = preparedStatement.executeQuery()) {
                // 如果有查询结果
                if (resultSet.next()) {
                    unitPrice = new BigDecimal(resultSet.getString("price"));// 将 VARCHAR 类型的单价转换为 BigDecimal 类型
                }
            }
        }
        return unitPrice; // 返回获取到的单价
    }

    /**
     * 获取当前库存。
     *
     * @param conn       数据库连接对象
     * @param clothingId 服装ID
     * @return 服装的当前库存
     * @throws SQLException 如果数据库操作出现异常
     */
    private int getCurrentStock(Connection conn, String clothingId) throws SQLException {
        int currentStock = 0;// 初始库存为0
        // 使用预处理语句查询 clothing 表中指定 clothingId 的库存
        try (PreparedStatement preparedStatement = conn.prepareStatement("SELECT quantity FROM clothing WHERE clothingid = ?")) {
            preparedStatement.setString(1, clothingId);// 设置 SQL 语句中的参数
            // 执行查询并获取结果集
            try (ResultSet resultSet = preparedStatement.executeQuery()) {
                // 如果有查询结果
                if (resultSet.next()) {
                    currentStock = resultSet.getInt("quantity");// 获取库存数量
                }
            }
        }
        return currentStock;// 返回获取到的库存
    }

    /**
     * 更新 Clothing 表中对应 clothingId 的库存。
     *
     * @param conn       数据库连接对象
     * @param clothingId 服装ID
     * @param newStock   新的库存数量
     * @throws SQLException 如果数据库操作出现异常
     */
    private void updateClothingStock(Connection conn, String clothingId, int newStock) throws SQLException {
        String sql = "UPDATE clothing SET quantity = ? WHERE clothingid = ?"; // 更新库存的 SQL 语句
        // 使用预处理语句设置参数并执行更新操作
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置 SQL 语句中的参数
            pstmt.setInt(1, newStock);
            pstmt.setString(2, clothingId);
            pstmt.executeUpdate(); // 执行更新操作
        }
    }

    /**
     * 插入销售记录到 Sale 表。
     *
     * @param conn           数据库连接对象
     * @param sale           销售对象
     * @param totalAmount    总金额
     * @param remainingStock 剩余库存
     * @throws SQLException 如果数据库操作出现异常
     */
    private void insertSaleRecord(Connection conn, Sale sale, BigDecimal totalAmount, int remainingStock) throws SQLException {
        String sql = "INSERT INTO sale (saleid, clothingid, quantitysold, totalamount, remainingstock, saledate) VALUES (?, ?, ?, ?, ?, ?)";// SQL 插入语句
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            // 设置 SQL 语句中的参数
            pstmt.setString(1, sale.getSaleId());
            pstmt.setString(2, sale.getClothingId());
            pstmt.setString(3, sale.getQuantitySold());
            pstmt.setBigDecimal(4, totalAmount);
            pstmt.setInt(5, remainingStock);
            pstmt.setString(6, sale.getSaleDate());
            pstmt.executeUpdate();// 执行插入操作
        }
    }

    /**
     * 异步添加销售记录。
     *
     * @param sale 销售对象
     * @return CompletableFuture，表示异步操作的结果
     */
    @Override
    public CompletableFuture<Void> addSaleAsync(T sale) {
        return CompletableFuture.runAsync(() -> {
            try (Connection conn = DruidUtil.getConnection()) {
                if (isValidInput(sale)) {
                    Sale validSale = (Sale) sale;
                    // 检查服装ID是否存在
                    if (isClothingIdValid(conn, validSale.getClothingId())) {
                        // 检查销售ID是否唯一
                        if (isSaleIdUnique(conn, validSale.getSaleId())) {
                            BigDecimal unitPrice = getUnitPrice(conn, validSale.getClothingId());
                            BigDecimal quantitySold = new BigDecimal(validSale.getQuantitySold());
                            BigDecimal totalAmount = quantitySold.multiply(unitPrice);
                            int currentStock = getCurrentStock(conn, validSale.getClothingId());
                            if (currentStock >= quantitySold.intValue()) {
                                updateClothingStock(conn, validSale.getClothingId(), currentStock - quantitySold.intValue());
                                insertSaleRecord(conn, validSale, totalAmount, currentStock - quantitySold.intValue());
                                showInformationAlert("成功", "销售记录已添加");
                            } else {showErrorAlert("错误", "库存不足，无法完成销售记录添加。");}
                        } else {showErrorAlert("错误", "销售ID重复，无法完成销售记录添加。");}
                    } else {showErrorAlert("错误", "服装ID不存在，无法完成销售记录添加。");}
                } else {showErrorAlert("错误", "销售记录不完整，无法完成添加。");}
            } catch (SQLException e) {
                e.printStackTrace();
                showErrorAlert("错误", "发生数据库错误，无法完成操作。");
            }
        }, executorService);
    }

    /**
     * 异步删除销售记录。
     *
     * @param sale 销售对象
     * @return CompletableFuture，表示异步操作的结果
     */
    @Override
    public CompletableFuture<Void> deleteSaleAsync(T sale) {
        return CompletableFuture.runAsync(() -> {
            try (Connection conn = DruidUtil.getConnection()) {
                if (sale instanceof Sale) {
                    Sale saleToDelete = (Sale) sale;
                    StringBuilder sqlBuilder = new StringBuilder("DELETE FROM sale WHERE 1=1");// 构建 SQL 语句
                    // 添加过滤条件（模糊删除，仅处理非空的条件）
                    if (isValidString(saleToDelete.getSaleId())) {sqlBuilder.append(" AND saleid LIKE '%").append(saleToDelete.getSaleId()).append("%'");}
                    if (isValidString(saleToDelete.getClothingId())) {sqlBuilder.append(" AND clothingid LIKE '%").append(saleToDelete.getClothingId()).append("%'");}
                    if (isValidString(saleToDelete.getQuantitySold())) {sqlBuilder.append(" AND quantitysold LIKE '%").append(saleToDelete.getQuantitySold()).append("%'");}
                    if (isValidString(saleToDelete.getSaleDate())) {sqlBuilder.append(" AND saledate LIKE '%").append(saleToDelete.getSaleDate()).append("%'");}
                    // 创建 PreparedStatement
                    try (PreparedStatement pstmt = conn.prepareStatement(sqlBuilder.toString())) {
                        int rowsAffected = pstmt.executeUpdate();// 执行删除操作
                        // 显示删除结果提示
                        Platform.runLater(() -> {
                            if (rowsAffected > 0) {
                                showInformationAlert("成功", rowsAffected + " 条有关的销售记录已删除");
                            } else {showErrorAlert("警告", "未删除任何记录，请确保输入正确的删除条件。");}
                        });
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
                Platform.runLater(() -> {showErrorAlert("错误", "发生数据库错误，无法完成操作。");});// 显示错误提示
            }
        }, executorService);
    }

    /**
     * 异步计算单个销售金额。
     *
     * @param clothingId 服装ID
     * @param startTime  开始日期
     * @param endTime    结束日期
     * @return CompletableFuture，包含计算结果的字符串
     */
    @Override
    public CompletableFuture<String> calculateMoney(String clothingId, String startTime, String endTime) {
        // 确保输入完整性
        if (clothingId.isEmpty() || startTime.isEmpty() || endTime.isEmpty()) {
            CompletableFuture<String> incompleteInputFuture = new CompletableFuture<>();
            incompleteInputFuture.completeExceptionally(new IllegalArgumentException("请提供完整的服装ID、开始日期和结束日期。"));
            return incompleteInputFuture;
        }
        return CompletableFuture.supplyAsync(() -> {
            try (Connection conn = DruidUtil.getConnection()) {
                if (isClothingIdValid(conn, clothingId)) {
                    String sql = "SELECT SUM(totalamount) FROM sale WHERE clothingid = ? AND saledate BETWEEN ? AND ?";
                    try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                        pstmt.setString(1, clothingId);
                        pstmt.setString(2, startTime);
                        pstmt.setString(3, endTime);
                        try (ResultSet resultSet = pstmt.executeQuery()) {
                            if (resultSet.next()) {
                                double totalAmount = resultSet.getDouble(1);
                                if (totalAmount > 0) {
                                    // 返回格式化后的字符串
                                    return String.format("在时间段 %s 到 %s，服装 %s 的销售总金额为 %.2f 元", startTime, endTime, clothingId, totalAmount);
                                } else {
                                    Platform.runLater(() -> showAlert("提示", "在此时间内没有销售", Alert.AlertType.INFORMATION));
                                }
                            } else {
                                Platform.runLater(() -> showAlert("提示", "没有此服装的销售记录", Alert.AlertType.INFORMATION));
                            }
                        }
                    }
                } else {
                    Platform.runLater(() -> showAlert("错误", "服装ID不存在，无法计算销售金额。", Alert.AlertType.ERROR));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null; // 返回默认值
        }, executorService);
    }

    /**
     * 异步计算所有销售项在给定时间范围内的总金额。
     *
     * @param startTime 开始日期
     * @param endTime   结束日期
     * @return CompletableFuture，包含计算结果的字符串
     */
    @Override
    public CompletableFuture<String> calculateAllMoney(String startTime, String endTime) {
        return CompletableFuture.supplyAsync(() -> {
            try (Connection conn = DruidUtil.getConnection()) {
                String sql = "SELECT SUM(totalamount) FROM sale WHERE saledate BETWEEN ? AND ?";
                try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                    pstmt.setString(1, startTime);
                    pstmt.setString(2, endTime);
                    try (ResultSet resultSet = pstmt.executeQuery()) {
                        if (resultSet.next()) {
                            double totalAmount = resultSet.getDouble(1);
                            if (totalAmount > 0) {
                                // 返回格式化后的字符串
                                return String.format("在时间段 %s 到 %s，所有销售项的总金额为 %.2f 元", startTime, endTime, totalAmount);
                            } else {
                                Platform.runLater(() -> showAlert("提示", "在此时间内没有销售", Alert.AlertType.INFORMATION));
                            }
                        } else {
                            Platform.runLater(() -> showAlert("提示", "没有销售记录", Alert.AlertType.INFORMATION));
                        }
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null; // 返回默认值
        }, executorService);
    }
}
